import { CydonElement, watch } from 'cydon'
import view from './view'
import 'uno.css'
import 'virtual:unocss-devtools'
import '@cydon/ui/components/TabContainer'
import '@cydon/ui/src/c-message.styl'
import { error } from '@cydon/ui/Message'
import { load, save, world } from './store'
import { loadWasm } from './game'
import { updatables } from './tino'
import { autoload } from './util'

/** 当前时间 */
export let tick = 0,
	/** 上次时间 */
	lastTick = 0

class GameMenu extends CydonElement {
	/** 显示图块详细信息 */
	showDetails = false
	/** 在地图上显示建筑等级 */
	showLevel!: boolean
	showEff!: boolean
	showExtra!: boolean
	showProgress!: boolean
	/** 触摸开始距离 */
	distance = 0
	offsetX = 0
	offsetY = 0
	/** 是否锁定摄像机 */
	camLock = false
	/** 速度 */
	speed = 1
	/** 自动保存周期 */
	autosave = 10

	//isExchange = false

	get selectedSlot() {
		return view.selectedSlot
	}

	async connectedCallback() {
		await load(sessionStorage.getItem('world')!)
		await loadWasm(view.setTexture.bind(view))
		this.resetCam()
		await autoload(this)
		this.showLevel = (world.opts & 1) != 0
		this.showEff = (world.opts & 2) != 0
		this.showExtra = (world.opts & 4) != 0
		this.showProgress = (world.opts & 8) != 0
		super.connectedCallback()
		watch(this, function (this: GameMenu) {
			const {
				showLevel = false,
				showEff = false,
				showExtra = true,
				showProgress = true
			} = this
			view.setOptions((showLevel ? 1 : 0) | (showEff ? 2 : 0) |
				(showExtra ? 4 : 0) | (showProgress ? 8 : 0))
		})
		addEventListener('beforeunload', () => save())
		updatables.add(tick => {
			world.stats.playTime++
			if (this.autosave && tick % this.autosave == 0)
				save()
		})
		this.update()
	}

	onClick(e: MouseEvent) {
		view.select(e.offsetX, e.offsetY)
		this.updateValue('selectedSlot')
	}
	//#region 鼠标控制
	onMouseMove(e: MouseEvent) {
		e.preventDefault()
		if (this.distance)
			view.offset = [this.offsetX - e.offsetX,
			this.offsetY - e.offsetY]
	}
	onMouseDown(e: MouseEvent) {
		if (e.button == 0 && !this.camLock) {
			this.distance = 1
			this.offsetX += e.offsetX
			this.offsetY += e.offsetY
		}
	}
	onMouseUp(e: MouseEvent) {
		if (e.button == 0) {
			this.distance = 0
			if (!this.camLock && e.type == 'mouseup') {
				this.offsetX -= e.offsetX
				this.offsetY -= e.offsetY
			}
		}
	}
	onWheel(e: WheelEvent) {
		if (!this.camLock) {
			const dt = Math.sign(e.deltaY)
			const scale = view.scale
			if (dt > 0 && scale > 1 / 200 || dt < 0 && scale < 0.1) {
				view.scale = 1 / (1 / scale + dt)
			}
			view.offset = [view.offset[0] - e.offsetX * dt * .03,
			view.offset[1] - e.offsetY * dt * .03]
		}
	}
	//#endregion
	//#region 触摸控制
	onTouchStart(e: TouchEvent) {
		if (!this.camLock) {
			const [a, b] = e.touches
			if (e.touches.length == 2) { // 双指触摸
				this.offsetX += a.clientX + b.clientX >> 1
				this.offsetY += a.clientY + b.clientY >> 1
				const dx = a.pageX - b.pageX
				const dy = a.pageY - b.pageY
				this.distance = Math.sqrt(dx * dx + dy * dy) // 计算两个触点之间的距离
			} else {
				this.distance = 1
				this.offsetX += a.clientX
				this.offsetY += a.clientY
			}
		}
	}
	onTouchEnd(e: TouchEvent) {
		this.distance = 0
		if (!this.camLock) {
			this.offsetX -= e.changedTouches[0].clientX
			this.offsetY -= e.changedTouches[0].clientY
		}
	}
	onTouchMove(e: TouchEvent) {
		e.preventDefault()
		const touches = e.touches
		if (this.distance) {
			const [touch] = touches
			view.offset = [this.offsetX - touch.clientX,
			this.offsetY - touch.clientY]
			if (touches.length == 2) { // 双指触摸
				const dx = touch.pageX - touches[1].pageX
				const dy = touch.pageY - touches[1].pageY
				const dis = Math.sqrt(dx * dx + dy * dy) // 计算两个触点之间的距离
				view.scale = view.slotSize * dis / view.canvas.width / this.distance
			}
		}
	}
	//#endregion
	/** 返回 */
	back() {
		save()
		location.href = './index.html'
	}
	/** 重置视图 */
	resetCam() {
		this.offsetX = this.offsetY = 0
		view.offset = [0, 0]
		view.scale = view.slotSize / view.canvas.width
	}
	/** 更新 */
	update() {
		setTimeout(() => this.update(), this.speed ? 1000 / Math.min(this.speed, 5) : 1000)
		if (!this.speed)
			return
		lastTick = tick++
		for (const f of updatables)
			f(tick)
	}
}
customElements.define('game-menu', GameMenu)

// 禁止滚动
document.body.style.overflowY = 'hidden'

// 错误处理
addEventListener('error', e => error(e.message + ' ' + e.error?.stack))
addEventListener('unhandledrejection', e => error(e.reason))

declare global {
	interface HTMLElementTagNameMap {
		'game-menu': GameMenu
	}
}
